import { ApolloClient } from 'apollo-client'
import { getMainDefinition } from 'apollo-utilities'
import { ApolloLink, split } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { WebSocketLink } from 'apollo-link-ws'
import { onError } from 'apollo-link-error'
import { InMemoryCache } from 'apollo-cache-inmemory'

class AppplloClient {
  client

  getClient = () => this.client

  setClient = function setApolloClient(client) {
    this.client = client
  }

  makeClient = (url, token) => {
    const httpLink = new HttpLink({
      uri: `http://${url}/v1alpha1/graphql`,
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })

    const wsLink = new WebSocketLink({
      uri: `ws://${url}/v1alpha1/graphql`,
      options: {
        reconnect: true,
        connectionParams: {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        },
      },
    })

    const terminatingLink = split(
      ({ query }) => {
        const { kind, operation } = getMainDefinition(query)
        return kind === 'OperationDefinition' && operation === 'subscription'
      },
      wsLink,
      httpLink,
    )

    const errorLink = onError(({ graphQLErrors, networkError, ...others }) => {
      if (graphQLErrors) {
        graphQLErrors.forEach(({ message, locations, path }) => {
          console.log('GraphQL error', message)
        })
      }

      if (graphQLErrors) {
        graphQLErrors.forEach(err => console.log('GraphQL error', err.message))
      }

      if (networkError) {
        console.log('Network error', networkError)
      }

      console.log('others error', others)
    })

    const link = ApolloLink.from([errorLink, terminatingLink])

    const cache = new InMemoryCache()

    return new ApolloClient({
      link,
      cache,
    })
  }
}

export default new AppplloClient()
